﻿using Microsoft.Practices.EnterpriseLibrary.Common.Configuration;
using Microsoft.Practices.EnterpriseLibrary.Logging;
using Microsoft.Practices.EnterpriseLibrary.Logging.Formatters;
using Microsoft.Practices.EnterpriseLibrary.Logging.TraceListeners;
using Microsoft.Xrm.Sdk;
using System;
using System.Diagnostics;
using ZhongchenZhou.EnterpriseLibrary.Logging.DynamicsCrm2011.Configuration;

namespace ZhongchenZhou.EnterpriseLibrary.Logging.DynamicsCrm2011
{
    [ConfigurationElementType(typeof(DynamicsCrm2011TraceListenerData))]
    public class DynamicsCrm2011TraceListener : CustomTraceListener
    {
        private IOrganizationService _service;

        public DynamicsCrm2011TraceListener(IOrganizationService service, ILogFormatter formatter)
        {
            this._service = service;
            Formatter = formatter;
        }

        /// <summary>
        /// Delivers the trace data to the underlying database.
        /// </summary>
        /// <param name="eventCache">The context information provided by <see cref="System.Diagnostics"/>.</param>
        /// <param name="source">The name of the trace source that delivered the trace data.</param>
        /// <param name="eventType">The type of event.</param>
        /// <param name="id">The id of the event.</param>
        /// <param name="data">The data to trace.</param>
        public override void TraceData(TraceEventCache eventCache, string source, TraceEventType eventType, int id, object data)
        {
            if ((this.Filter == null) || this.Filter.ShouldTrace(eventCache, source, eventType, id, null, null, data, null))
            {
                if (data is LogEntry)
                {
                    LogEntry logEntry = data as LogEntry;

                    WriteToCrm(logEntry, this._service);
                }
                else if (data is string)
                {
                    Write(data as string);
                }
                else
                {
                    base.TraceData(eventCache, source, eventType, id, data);
                }
            }
        }

        protected override string[] GetSupportedAttributes()
        {
            return new string[2] { "formatter", "crmConnectionStringName" };
        }

        public override void Write(string message)
        {
            WriteToCrm(0, 5, TraceEventType.Information, string.Empty, DateTime.Now, string.Empty,
                                            string.Empty, string.Empty, string.Empty, null, null, message, this._service);
        }

        public override void WriteLine(string message)
        {
            Write(message);
        }

        private Guid WriteToCrm(LogEntry logEntry, IOrganizationService service)
        {
            Entity entity = new Entity("zzhou_entliblog");

            entity["zzhou_eventid"] = logEntry.EventId;
            entity["zzhou_priority"] = logEntry.Priority;
            entity["zzhou_severity"] = new OptionSetValue((int)logEntry.Severity);
            entity["zzhou_title"] = logEntry.Title;
            entity["zzhou_timestamp"] = logEntry.TimeStamp;
            entity["zzhou_machinename"] = logEntry.MachineName;
            entity["zzhou_appdomainname"] = logEntry.AppDomainName;
            entity["zzhou_processid"] = logEntry.ProcessId;
            entity["zzhou_processname"] = logEntry.ProcessName;
            entity["zzhou_threadname"] = logEntry.ManagedThreadName;
            entity["zzhou_win32threadid"] = logEntry.Win32ThreadId;
            entity["zzhou_message"] = logEntry.Message;

            if (Formatter != null)
                entity["zzhou_formattedmessage"] = Formatter.Format(logEntry);
            else
                entity["zzhou_formattedmessage"] = logEntry.Message;

            Guid logId = service.Create(entity);
            return logId;
        }

        private Guid WriteToCrm(int eventId, int priority, TraceEventType severity, string title, DateTime timeStamp,
                                            string machineName, string appDomainName, string processId, string processName,
                                            string managedThreadName, string win32ThreadId, string message, IOrganizationService service)
        {
            Entity entity = new Entity("zzhou_entliblog");

            entity["zzhou_eventid"] = eventId;
            entity["zzhou_priority"] = priority;
            entity["zzhou_severity"] = new OptionSetValue((int)severity);
            entity["zzhou_title"] = title;
            entity["zzhou_timestamp"] = timeStamp;
            entity["zzhou_machinename"] = machineName;
            entity["zzhou_appdomainname"] = appDomainName;
            entity["zzhou_processid"] = processId;
            entity["zzhou_processname"] = processName;
            entity["zzhou_threadname"] = managedThreadName;
            entity["zzhou_win32threadid"] = win32ThreadId;
            entity["zzhou_message"] = message;
            entity["zzhou_formattedmessage"] = message;

            Guid logId = service.Create(entity);
            return logId;
        }

    }
}
